#pragma once

#include "parentpanel.h"
#include "textbutton.h"

class TabbedPanel;

/** manages an entry in the tabbed pane */
class TabEntry
{
protected:
	/** the button (at the top) that switches this entry on */
	Button * m_button;
	/** the content that will show when this tab is on */
	TabbedPanel * m_tabPanel;
	/** what is being shown in the main content pane when this tab is selected */
	Panel * m_content;
public:
	Button * getButton(){return m_button;}
	Panel * getContent(){return m_content;}
	TabbedPanel * getTabbedPanel(){return m_tabPanel;}
	/**
	 * @param a_label text to describe the tab
	 * @param a_parent the tabbed pane context
	 * @param a_id which tabbed pane content this button triggers
	 */
	TabEntry(Button * a_newButton, Panel * a_content, TabbedPanel * a_parent)//, const int & a_id)
		:m_button(a_newButton),m_tabPanel(a_parent),m_content(a_content)//,tabID(a_id)
	{}
	TabEntry():m_tabPanel(0){}//,tabID(UNDEFINED){}
	/** used by the vector class */
	TabEntry & operator=(const TabEntry & te)
	{
		m_button=te.m_button;
		m_tabPanel=te.m_tabPanel;
		m_content=te.m_content;
		return *this;
	}
	void release(){if(m_button){delete m_button;m_button=0;}}
};

class TabbedPanel : public ParentPanel
{
protected:
	static const int UNDEFINED = -1;
	static const int CHILD_SPACING = 1;
	/** the tabs of this panel */
	TemplateVectorList<TabEntry> m_tabEntries;
	/** keeps the buttons that will switch the tabbed content */
	ParentPanel m_tabBox;
	/** where to draw the content */
	SRect m_contentPane;
	/** what to draw as the content */
	Panel * m_content;
	void setContentPanel(Panel * a_content){m_content=a_content;}
public:
	/**
	 * @param a panel that is in this tabbed panel.
	 * @return the button that selects the given tabbed panel
	 */
	Button * getButtonOf(Panel * a_contentPanel)
	{
		TabEntry * te;
		for(int i = 0; i < m_tabEntries.size(); ++i)
		{
			te = &m_tabEntries.get(i);
			if(te->getContent() == a_contentPanel)
			{
				return te->getButton();
			}
		}
		return 0;
	}
	void refreshTabs()
	{
		m_tabBox.requestChildAreaRefresh();
		m_tabBox.refreshArea();
	}
	void addTab(Button * a_tab)
	{
		m_tabBox.addChild(a_tab);
	}
	void release()
	{
		for(int i = 0; i < m_tabEntries.size(); ++i)
		{
			m_tabEntries.get(i).release();
		}
		m_tabEntries.release();
		ParentPanel::release();
	}
	TabbedPanel():m_tabEntries(10),m_content(0)
	{addChild(&m_tabBox);m_tabBox.setAutoArrangeGrid(true);m_tabBox.setDragAndDropChild(true);}
	bool update(const int & a_ms)
	{
		bool updated = ParentPanel::update(a_ms);
		if(m_content)
			updated |= m_content->update(a_ms);
		return updated;
	}
	/** sets the area of the tabbed panel, resizing all child panels */
	void setArea(const SRect a_rect)
	{
		Panel::setArea(a_rect);
		TemplateVector<Panel*> * tabs = m_tabBox.getChildren();
		// TODO get preferred height of the tab box?
		int tabBoxHeight = (tabs->size()>0)
			?tabs->get(0)->getArea()->getHeight()
			:0;	//(m_lastButton)
				//?m_lastButton->getArea()->getHeight()
				//:0;
		m_tabBox.setArea(a_rect);
		m_tabBox.getArea()->setHeight(tabBoxHeight);
		// setup the content pane, and all tabbed contents to match
		m_contentPane.set(a_rect);
		m_contentPane.setMinY(a_rect.getMinY()+tabBoxHeight);
		for(int i = 0; i < m_tabEntries.size(); ++i)
		{
			m_tabEntries.get(i).getContent()->setArea(m_contentPane);
		}
		refreshTabs();
	}
	void refresh()
	{
		setArea(*getArea());
		refreshTabs();
	}

	static void setTabAction(void * a_tabEntry)
	{
		TabEntry * te = (TabEntry*)a_tabEntry;
		TabbedPanel * tb = te->getTabbedPanel();
		Button * b;
		TemplateVectorList<TabEntry> * tabButtons = &tb->m_tabEntries;
		for(int i = 0; i < tabButtons->size(); ++i)
		{
			b = tabButtons->get(i).getButton();
			if(b != te->getButton())
			{
				b->setOn(false);
			}
		}
		te->getButton()->setOn(true);
		tb->setContentPanel(te->getContent());
		tb->refresh();
		tb->setDirty(0);
	}
	void insertContentPanel(const int & a_index, Panel * a_contentPanel, Button * a_newButton)
	{
		// add tab and content
		a_contentPanel->setParent(this);
		m_tabEntries.insert(a_index, TabEntry(a_newButton, a_contentPanel, this));
		TabEntry * tabEntry = &m_tabEntries.get(a_index);
		Button * b = tabEntry->getButton();
		b->setAction((ButtonCallbackFunction)setTabAction,tabEntry);
		b->setToggleable(true);
		m_tabBox.insertChild(a_index, tabEntry->getButton());
		// setup the tab
		refreshTabs();
		// setup the content panel
		a_contentPanel->setArea(m_contentPane);
		setDirty(0);
	}
	/** add a content pane and label */
	void addContentPanel(Panel * a_conentPanel, Button * a_newButton)
	{insertContentPanel(m_tabEntries.size(), a_conentPanel, a_newButton);}
	/** TODO merge with insertContentPanel somehow */
	void setContentPanel(const int & a_index, Panel * a_contentPanel, Button * a_newButton)
	{
		a_contentPanel->setParent(this);
		m_tabEntries.get(a_index).release();
		m_tabEntries.set(a_index, TabEntry(a_newButton, a_contentPanel, this));
		TabEntry * tabEntry = &m_tabEntries.get(a_index);
		Button * b = tabEntry->getButton();
		b->setAction((ButtonCallbackFunction)setTabAction,tabEntry);
		b->setToggleable(true);
		m_tabBox.setChild(a_index, tabEntry->getButton());
		// setup the tab
		refreshTabs();
		// setup the content panel
		a_contentPanel->setArea(m_contentPane);
		setDirty(0);
	}
	int currentIndex()
	{
		for(int i = 0; i < m_tabEntries.size(); ++i)
		{
			if(m_tabEntries.get(i).getContent() == m_content)
				return i;
		}
		return -1;
	}
	void advanceTab(const int & a_direction)
	{
		int max = m_tabEntries.size();
		if(max > 0)
		{
			int nextIndex = currentIndex();
			do{
				nextIndex += a_direction;
				while(nextIndex < 0)nextIndex+=max;
				while(nextIndex >= max)nextIndex-=max;
			}while(m_tabEntries.get(nextIndex).getContent() == 0);
			setContentPanel(m_tabEntries.get(nextIndex).getContent());
		}
	}
	bool handleEvent(const SDL_Event & e)
	{
		bool handled = false;
		bool dirty = false;
		switch(e.type)
		{
		case SDL_KEYDOWN:
			switch(e.key.keysym.sym)
			{
			case SDLK_TAB:
					advanceTab(
						((e.key.keysym.mod & KMOD_SHIFT)?-1:1));
					dirty = true;
				break;
			}
		}
		if(!handled)
		{
			handled = m_tabBox.handleEvent(e);
		}
		if(!handled && m_content)
		{
			handled = m_content->handleEvent(e);
		}
		return handled || dirty;
	}
	void draw(SDL_Surface * a_surface)
	{
		ParentPanel::draw(a_surface);
		//VSDL_drawRect(a_surface, &m_contentPane, 0, 5);
		if(m_content)
		{
			m_content->draw(a_surface);
		}
	}
};